/**
 * Copyright (c) 2022.08.22
 * Author: MengXii
 */

#include <glog/logging.h>
#include <gtest/gtest.h>

#include <string>

#include "coin2/base/memory/mem_slice.h"
#include "coin2/base/packer.h"
#include "coin2/base/unpacker.h"
#include "coin2/controller/base_type.h"
#include "coin2/controller/message_assembler.h"

using namespace coin2::base;
using namespace coin2::controller;

class AssemblerTester : public MessageAssembler::Callback {
 public:
  AssemblerTester() : q_(this) {}
  void Push(memory::MemSlice buffer) { q_.OnPacketReceived(std::move(buffer)); }
  void SetStr(std::string str) { test_str = str; }

  // inherit form  MessageAssembler::Callback
  void OnProcessMessage(memory::MemSlice data) override;
  void OnBroken() override;

 private:
  MessageAssembler q_;
  std::string test_str;
};

void AssemblerTester::OnProcessMessage(memory::MemSlice data) {
  Unpacker unpk(data.Begin(), data.GetUsedSize());
  std::string s = unpk.PopString();
  LOG(INFO) << "test_str: " << test_str << " msg: " << s;
  EXPECT_EQ(s, test_str);
}

void AssemblerTester::OnBroken() { LOG(ERROR) << "On Broken"; }

TEST(MessageTester, AssemblerTest) {
  AssemblerTester tester;
  Packer pk;
  // case 1
  std::string test_str = "test_test_test_test";
  auto size = test_str.size();
  tester.SetStr(test_str);
  pk << test_str;
  pk.Pack();
  memory::MemSlice buffer(pk.TakeBuffer());

  memory::MemSlice buffer2(buffer);
  buffer.SetRelativeEndPointer(size / 2);
  buffer2.AdjustBeginPointer(size / 2);
  tester.Push(buffer);
  tester.Push(buffer2);

  // case 2
  pk.Reset();
  test_str = "assembler_test!!";
  size = test_str.size();
  tester.SetStr(test_str);
  pk << test_str;
  pk.Pack();
  buffer = pk.TakeBuffer();
  buffer2 = buffer;
  memory::MemSlice buffer3(buffer);
  buffer.SetRelativeEndPointer(size / 3);

  buffer2.AdjustBeginPointer(size / 3);
  buffer2.SetRelativeEndPointer(size / 3);

  buffer3.AdjustBeginPointer(size / 3 + size / 3);
  tester.Push(buffer);
  tester.Push(buffer2);
  tester.Push(buffer3);
}